#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project ：turbo
@File    ：views.py
@Author  ：赵加响
@Date    ：2023/4/6 10:17
@Desc    ：
"""
from django.db import transaction
from django.utils.translation import gettext_lazy as _
from rest_framework.exceptions import ValidationError
from rest_framework.views import APIView

from apps.accounts.models import User
from apps.rbac.handlers import generate_menu_tree, generate_role_tree, generate_sensitive_menu_structure_tree
from apps.rbac.models import Role, RoleMenuOperate, MenuOperate, MenuSensitiveField, Menu, SensitiveField, \
    UserMenuSensitiveField
from apps.rbac.serializers import RoleSerializer
from bases.response import SuccessResponse
from bases.viewsets import APIModelViewSet
from constants import LANGUAGE_ZH


class RoleViewSet(APIModelViewSet):
    queryset = Role.objects.all().order_by('id')
    serializer_class = RoleSerializer
    filter_fields = ('code', 'is_admin')


class RoleTree(APIView):

    def get(self, request):
        roles = Role.objects.filter(parent__isnull=True).order_by('-is_admin', 'id')
        role_list = list()

        localization = getattr(request, 'LANGUAGE_CODE', LANGUAGE_ZH)

        for role in roles:
            role_dict = dict()
            role_dict['id'] = role.id
            role_dict['name'] = role.name_zh if localization == LANGUAGE_ZH else role.name_en

            role_list.append(role_dict)

            generate_role_tree(role_dict, role.id, localization)

        return SuccessResponse(role_list)


class RoleMenuAuthorize(APIView):

    def get(self, request):
        role_id = request.GET.get('role')
        parent = request.GET.get('parent')

        data = {}
        menu_list = []
        checked_list = []

        localization = getattr(request, 'LANGUAGE_CODE', LANGUAGE_ZH)
        generate_menu_tree(menu_list, parent, checked_list, role_id, localization)
        menu_operates = MenuOperate.objects.values_list('id', flat=True)

        data['menu'] = menu_list
        data['checked'] = checked_list
        data['check'] = list(menu_operates)
        return SuccessResponse(data)

    @transaction.atomic
    def post(self, request):
        """
        角色授权
            该系统角色授权略不同于Targa基类的系统，属于优化
        """
        role_id = request.data['role']
        selected = request.data['selected']

        role_menu_operates = RoleMenuOperate.objects.filter(role_id=role_id)

        if role_menu_operates.exists():
            # 删除已经存在数据角色权限，这些数据本身也没什么用处
            role_menu_operates.delete()

        for select in selected:
            if isinstance(select, int):
                try:
                    menu_operate = MenuOperate.objects.get(id=select)
                except MenuOperate.DoesNotExist:
                    # Translators: 菜单操作关系表数据异常
                    raise ValidationError(_('menu operation relationship table data anomaly'))

                if RoleMenuOperate.objects.filter(role_id=role_id, menu_operate=menu_operate).exists():
                    try:
                        role_menu_operate = RoleMenuOperate.objects.get(role_id=role_id, menu_operate=menu_operate)
                    except RoleMenuOperate.DoesNotExist:
                        # Translators: 角色菜单操作表数据维护异常
                        raise ValidationError(_('role menu operation table data maintenance anomaly'))
                    role_menu_operate.is_active = True
                    role_menu_operate.save()
                else:
                    role_menu_operate = RoleMenuOperate()
                    role_menu_operate.is_active = True
                    role_menu_operate.role_id = role_id
                    role_menu_operate.menu_operate = menu_operate
                    role_menu_operate.save()

        return SuccessResponse()


class RoleAssignUser(APIView):

    def get(self, request):
        role_id = request.GET.get('role')
        role = Role.objects.get(id=role_id)
        data = dict()
        un_assigned_list = []
        un_assigned_users = User.objects.values('name', 'id').filter(is_active=True).order_by('id')
        assigned_list = User.objects.values_list('id', flat=True).filter(roles=role).order_by('id')

        for un_assigned_user in un_assigned_users:
            un_assigned = dict()
            un_assigned['key'] = un_assigned_user['id']
            un_assigned['label'] = un_assigned_user['name']
            un_assigned_list.append(un_assigned)

        data['un_assigned'] = un_assigned_list
        data['assigned'] = list(assigned_list)

        return SuccessResponse(data)

    @transaction.atomic
    def post(self, request):
        role_id = request.data['role']
        user_id_list = request.data['user']

        role = Role.objects.get(id=role_id)

        role_users = role.roles.all()

        for user in role_users:
            user.roles.remove(role)

        for user_id in user_id_list:
            user = User.objects.get(id=user_id)
            user.roles.add(role)

        return SuccessResponse()


class GetMenuStructureTree(APIView):

    def get(self, request):
        """
        获取敏感字段存在的菜单树
        @param request:
        @return:
        """
        menu_list = list()
        localization = getattr(request, 'LANGUAGE_CODE', LANGUAGE_ZH)
        generate_sensitive_menu_structure_tree(menu_list, None, localization)
        for menu in menu_list:
            if 'children' in menu:
                if len(menu['children']) == 0:
                    menu_list.remove(menu)

        return SuccessResponse(menu_list)


class MenuSensitiveFieldAuthorize(APIView):

    def get(self, request):
        """
        获取指定用户指定菜单下敏感字段的权限
        user_id:指定用户ID
        menu_id:指定菜单ID
        @param request:
        @return:
        """
        menu_id = request.GET.get('menu_id')
        user_id = request.GET.get('user_id')

        user_menu_sensitive_fields = UserMenuSensitiveField.objects.filter(user__id=user_id,
                                                                           menu_sensitive_field__menu__id=menu_id)

        menu_sensitive_dict = dict()
        for user_menu_sensitive_field in user_menu_sensitive_fields:
            menu_sensitive_dict[
                user_menu_sensitive_field.menu_sensitive_field.sensitive_field.code.lower()] \
                = user_menu_sensitive_field.permission_type

        return SuccessResponse(menu_sensitive_dict)

    @transaction.atomic
    def post(self, request):
        """
        菜单敏感字段授权
        user_id:授权目标用户ID
        menu_id:授权菜单ID
        sensitive_field:授权敏感字段
        permission_type：
            F:禁止
            R:只读
            W:读写
        @param request:
        @return:
        """
        user_id = request.data['user_id']
        menu_id = request.data['menu_id']
        field = request.data['sensitive_field']
        permission_type = request.data['permission_type']

        user = User.objects.get(id=user_id)
        sensitive_field = SensitiveField.objects.get(code__iexact=field)
        menu = Menu.objects.get(id=menu_id)

        try:
            menu_sensitive_field = MenuSensitiveField.objects.get(sensitive_field=sensitive_field, menu=menu)
        except MenuSensitiveField.DoesNotExist:
            menu_sensitive_field = MenuSensitiveField.objects.create(sensitive_field=sensitive_field, menu=menu)

        try:
            user_menu_sensitive_field = UserMenuSensitiveField.objects.get(user=user,
                                                                           menu_sensitive_field=menu_sensitive_field)
            user_menu_sensitive_field.permission_type = permission_type
            user_menu_sensitive_field.save()
        except UserMenuSensitiveField.DoesNotExist:
            UserMenuSensitiveField.objects.create(user=user, menu_sensitive_field=menu_sensitive_field,
                                                  permission_type=permission_type)

        return SuccessResponse()


class MenuSensitiveFieldBatchAuthorize(APIView):

    @transaction.atomic
    def post(self, request):
        """
        菜单敏感字段批量授权
        user_id:授权目标用户ID
        permission_type：
            F:全部禁止
            R:全部只读
            W:全部读写
        @param request:
        @return:
        """
        user_id = request.data['user_id']
        permission_type = request.data['permission_type']
        user = User.objects.get(id=user_id)

        UserMenuSensitiveField.objects.filter(user=user).delete()

        menu_sensitive_fields = MenuSensitiveField.objects.all()

        user_menu_sensitive_field = []

        for menu_sensitive_field in menu_sensitive_fields:
            user_menu_sensitive_field.append(
                UserMenuSensitiveField(user=user, menu_sensitive_field=menu_sensitive_field,
                                       permission_type=permission_type))

        UserMenuSensitiveField.objects.bulk_create(user_menu_sensitive_field)
        return SuccessResponse()
